package 牛客.查找;
/*
 *@Author: helen
 *@Date:   2021/4/21 12:52
 *@Description:
 题目描述
    有一个整数数组，请你根据快速排序的思路，找出数组中第K大的数。
    给定一个整数数组a,同时给定它的大小n和要找的K(K在1到n之间)，请返回第K大的数，保证答案存在。
    示例1
        输入      [1,3,5,2,2],5,3
        返回值     2
 */

import java.util.SortedMap;
import java.util.TreeMap;

public class 第K大的数 {
    public int findKth(int[] a, int n, int k) {
        // write code here
        int result = QuickFind(a, 0, n - 1, k);
        return result;
    }
    /*方法一：使用快速排序的思想，从大到小排序，每比较完一轮，判断此时走到的数组的索引值i：
     i == k - 1,则返回此时索引的数组值
     i > k - 1,则第k大的数在此时索引的左边，递归数组左半边
     i < k - 1,则第k大的数在此时索引的右边，递归数组右半边
     时间复杂度O(n)
     */
    public int QuickFind(int[] a, int start, int end, int k){
        int i = start;
        int j = end;
        while (i < j){
            while (i < j && a[i] >= a[j]) j--;
            if(i < j){
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
                i++;
            }
            while (i < j && a[i] >= a[j]) i++;
            if(i < j){
                int t = a[i];
                a[i] = a[j];
                a[j] = t;
                j--;
            }
        }
        if(i < k - 1)
            return QuickFind(a, i+1, end, k);
        else if(i > k - 1)
            return QuickFind(a, start, i - 1, k);
        else return a[i];
    }
    /*方法二：适合海量数据，利用SortedMap每插入一个数据其结构都是把键按小到大排好序的，
     map.firstKey为最小的key,map.last为最大的key,
     先把前面k个数作为key放进map,后面的数逐一和map.firstKey比较,
     若该数大于map.firstKey,则先remove(map.firstKey),再put(a[i],i)
     若该数小于或等于map.firstKey，则啥也不做
     时间复杂度O(n * log n)
     */
    public int FindK(int[] a, int n, int k){
        SortedMap<Integer, Integer> map = new TreeMap<>();
        for (int i = 0; i < n; i++) {
            if (i < k)
                map.put(a[i], i);
            else{
                if(a[i] > map.firstKey()) {
                    map.remove(map.firstKey());
                    map.put(a[i],i);
                }
            }
        }
        return map.firstKey();
    }

    public static void main(String[] args) {
        第K大的数 obj = new 第K大的数();
        int[] a = {1,3,5,2,2};
        int n = 5;
        int k = 4;
        int kth = obj.findKth(a, n, k);
        System.out.println(kth);
        System.out.println(obj.FindK(a, n, k));
    }
}
